/*
 * @FileName: [AbstractController.java]
 * 
 * @Package com.bcinfo.upp.admin.controller
 * 
 * 
 * Copyright (c) 2011-2015 BCINFO Technology Limited Com. All rights reserved.
 * 
 * This software is the confidential and proprietary information of BCINFO
 * Technology Limited Company ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only in accordance
 * with the terms of the contract agreement you entered into with RKY.
 * 
 * $Rev: 751 $ $LastChangedDate: 2013-11-06 13:33:28 +0800 (星期三, 06 十一月 2013) $
 * $LastChangedBy: yanhy $
 * 
 * @category bcinfo-upp
 * 
 * @version 1.1
 * 
 * @author $Author: yanhy $
 * 
 * Change History:[Formatter: author date description] <br/> 1 2 3
 */

package com.bcinfo.iccard.admin.controller;

import static com.bcinfo.iccard.admin.common.Constants.CURRENT_ROLE_PERMISSION;
import static com.bcinfo.iccard.admin.common.Constants.CURRENT_USER;

import java.io.IOException;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;

import com.bcinfo.iccard.admin.common.Constants;
import com.bcinfo.upp.ac.model.Operator;
import com.bcinfo.upp.ac.model.RolePermission;
import com.bcinfo.upp.ac.util.PermissionUtil;
import com.bcinfo.upp.audit.model.OpLog;
import com.bcinfo.upp.audit.service.OperationLogService;
import com.bcinfo.upp.exception.UppDataBaseException;
import com.bcinfo.upp.exception.UppException;
import com.bcinfo.upp.sys.service.ConfigureService;

/**
 * 抽象的控制器 <br/>
 * <p>
 * Description:<br/>
 * <p>
 * 提供公共的控制器方法、属性
 * 
 * <p>
 * For Examples <br/>
 * 
 * <PRE>
 * public class XxxControler extends AbstractController
 * </PRE>
 * <p>
 */
public abstract class AbstractController implements AdminController
{
    protected final Logger          _log      = Logger.getLogger(this.getClass());

    @Autowired
    protected OperationLogService   _operationLogService;

    /**
     * @Fields page : 分页页数，默认第一页
     */
    private int                     _page     = 1;

    /**
     * @Fields pageSize : 列表显示数量，默认为10条
     */
    private int                     _pageSize = 10;

    /**
     * @Fields request : 自动注入的HttpServletRequest 变量
     */
    @Autowired
    protected HttpServletRequest    request;

    /**
     * @Fields session : 自动注入的HttpSession变量
     */
    @Autowired
    protected HttpSession           session;

    /**
     * @Fields propertiesFactorBean : properties bean
     */
    @Autowired
    protected PropertiesFactoryBean _propertiesFactorBean;

    @Autowired
    private ConfigureService        _configureService;

    /**
     * 获取系统配置 <br/>
     * <p>
     * Description: 根据传入的key查询系统配置的值 <br/>
     * <p>
     * Author: yun<br/>
     * <p>
     * Date: 2013-6-8-上午10:53:15<br/>
     * <p>
     * 
     * @param key
     *            key
     * @return value
     * @throws UppDataBaseException
     * 
     */
    protected String getConfigByKey(String key) throws UppDataBaseException
    {
        return _configureService.getConfigByKey(key);
    }

    /**
     * 获取系统配置<br/>
     * <p>
     * Description: 根据传入的key查询系统配置的值，返回一个以‘，’拆分的数组 <br/>
     * <p>
     * Author: yun<br/>
     * <p>
     * Date: 2013-6-8-上午10:56:07<br/>
     * <p>
     * 
     * @param key
     * @return
     * @throws UppDataBaseException
     * 
     */
    protected String[] getConfigValueArrayByKey(String key) throws UppDataBaseException
    {
        return _configureService.getConfigsByKey(key);
    }

    /**
     * 生成token <br/>
     * <p>
     * Description: 每个form表单生成 一个token <br/>
     * <p>
     * Author: yun<br/>
     * <p>
     * Date: 2013-6-21-下午4:52:11<br/>
     * <p>
     * 
     * @return
     * 
     */
    @SuppressWarnings("unchecked")
    protected String generateToken()
    {
        Object obj = session.getAttribute("tokenStore");
        String token = DigestUtils.md5Hex(session.getId() + System.currentTimeMillis());
        Map<String, Date> tokenStore;

        if (obj == null)
        {
            tokenStore = new ConcurrentHashMap<String, Date>();
        }
        else
        {
            tokenStore = (Map<String, Date>) session.getAttribute("tokenStore");
        }

        tokenStore.put(token, new Date());
        session.setAttribute("tokenStore", tokenStore);

        return token;
    }

    /**
     * 
     * 
     * 判断对某个action 方法时候具有权限，在action方法调用之前，验证方法权限，根据结果进行相应处理
     * ，action二进制值和注意是资源id不是资源typeId<br/>
     * <br/>
     * <p>
     * Author: chenyc<br/>
     * <p>
     * Date: 2013-5-20-上午11:13:57<br/>
     * <p>
     * 
     * @param _actionBit
     * @param _resId
     * @return
     * 
     */
    protected boolean hasPermission(String _actionCode)
    {
        HttpSession se = request.getSession();
        Integer _actionBit = Constants.RESOURCE_ACTION_MAP.get(_actionCode);
        if (_actionBit == null)
        {

            // 不输出内部标签
            return false;
        }

        Long _resId = Constants.RESOURCE_RESOURCE_MAP.get(_actionCode);
        @SuppressWarnings("unchecked")
        Map<Long, RolePermission> map = (Map<Long, RolePermission>) se.getAttribute(CURRENT_ROLE_PERMISSION);

        Operator oper = (Operator) se.getAttribute(CURRENT_USER);

        if (oper == null)
        {
            return false;
        }
        if (oper.getOwner() == -1)
        {// 超级管理员
         // 输出内部标签
            return true;
        }
        if (map == null)
        {
            // 不输出内部标签
            return false;
        }
        RolePermission per = map.get(_resId);
        if (per == null)
        {
            // 不输出内部标签
            return false;
        }
        if (PermissionUtil.hasPermission(per.getActions(), _actionBit))
        {

            // 输出内部标签
            return true;
        }
        else
        {
            // 不输出内部标签
            return false;

        }

    }

    /**
     * 记录操作日志 <br/>
     * <p>
     * Description: 记录当前管理员的操作行为 <br/>
     * <p>
     * Author: yun<br/>
     * <p>
     * Date: 2013-4-26-上午11:46:51<br/>
     * <p>
     * 
     * @param opAction
     *            操作
     * @param opContent
     *            操作内容
     * 
     */
    protected void addLog(String opAction, String opContent)
    {
        OpLog opLog = new OpLog();
        opLog.setOpTime(new Date(System.currentTimeMillis()));
        opLog.setUserId(getOperatorId());
        opLog.setOpContent(opContent);
        opLog.setClientIp(request.getRemoteAddr());
        opLog.setOpAction(opAction);
        opLog.setOpModule(getMouduleCode());

        try
        {
            _operationLogService.add(opLog);
        }
        catch (UppDataBaseException e)
        {
            handleException(e);
        }
    }

    /**
     * 获取当前用户 <br/>
     * <p>
     * Description: 获取当前登录用户 <br/>
     * <p>
     * Author: yun<br/>
     * <p>
     * Date: 2013-4-24-下午5:51:51<br/>
     * <p>
     * 
     * @return 当前登录用户
     * 
     */
    protected Operator getCurrentOperator()
    {
        Object obj = session.getAttribute(CURRENT_USER);
        if (obj != null)
        {
            return (Operator) obj;
        }

        return null;
    }

    /**
     * 获取当前登录用户ID<br/>
     * <p>
     * Description: 获取当前登录用户ID，如果为空则返回null <br/>
     * <p>
     * Author: yun<br/>
     * <p>
     * Date: 2013-6-7-下午4:59:22<br/>
     * <p>
     * 
     * @return
     * 
     */
    protected Long getOperatorId()
    {
        Operator operator = getCurrentOperator();

        if (operator != null)
        {
            return operator.getOperatorId();
        }
        else
        {
            return null;
        }
    }

    /**
     * 
     * 
     * session 获取存放角色 资源和资源权限的map<br/>
     * <p>
     * Description: <br/>
     * <p>
     * Author: chenyc<br/>
     * <p>
     * Date: 2013-4-27-下午05:55:24<br/>
     * <p>
     * 
     * @param session
     * @return
     * 
     */
    @SuppressWarnings("unchecked")
    protected static Map<Long, RolePermission> getResRolePermissionMap(HttpSession session)
    {
        return (Map<Long, RolePermission>) session.getAttribute(CURRENT_ROLE_PERMISSION);
    }

    /**
     * 获取错误信息 <br/>
     * <p>
     * Description: 通过异常名获取返回的错误信息 <br/>
     * <p>
     * Author: yun<br/>
     * <p>
     * Date: 2013-4-25-上午10:54:20<br/>
     * <p>
     * 
     * @param exceptionName
     * @return 异常对应的错误信息
     * 
     */
    protected String getErrorMessage(String exceptionName)
    {
        try
        {
            return ((Properties) (_propertiesFactorBean.getObject())).getProperty(exceptionName);
        }
        catch (IOException e)
        {
            handleException(e);
            return "错误信息配置文件加载错误";
        }
    }

    protected int getPage()
    {
        String pageString = request.getParameter("page");

        if (StringUtils.isNotBlank(pageString))
        {
            return Integer.parseInt(pageString);
        }

        return _page;
    }

    protected int getPageSize()
    {
        String pageSizeString = request.getParameter("rows");

        if (StringUtils.isNotBlank(pageSizeString))
        {
            return Integer.parseInt(pageSizeString);
        }

        return _pageSize;
    }

    /**
     * 封装ajax返回Map的信息<br/>
     * <p>
     * Description: 将ajax方法返回的Map信息进行统一的封装，使用时只需调用此方法传入参数即可。<br>
     * <p>
     * 如果自定义消息customMsgDesc不为空则使用customMsgDesc，否则根据msgDesc去查找相应的异常信息。 <br/>
     * <p>
     * Author: yun<br/>
     * <p>
     * Date: 2013-6-6-下午2:49:13<br/>
     * <p>
     * 
     * @param opResult
     *            结果
     * @param msgType
     *            消息类型
     * @param msgDesc
     *            消息描述
     * @param customMsgDesc
     *            自定义消息
     * @return
     * 
     */
    protected Map<String, String> packageAjaxReturnMap(String opResult, String msgType, String msgDesc,
            String customMsgDesc)
    {
        Map<String, String> map = new HashMap<String, String>(4);

        map.put(ERROR_KEY_OP_RESULT, opResult);
        map.put(ERROR_KEY_MSG_TYPE, msgType);

        if (StringUtils.isNotBlank(customMsgDesc))
        {
            map.put(ERROR_KEY_MSG_DESC, customMsgDesc);
        }
        else
        {
            map.put(ERROR_KEY_MSG_DESC, getErrorMessage(msgDesc));
        }

        return map;

    }

    /**
     * 异常封装 <br/>
     * <p>
     * Description: 将繁琐的异常捕获用一个统一的方法来封装并返回封装后的Map <br/>
     * <p>
     * Author: yun<br/>
     * <p>
     * Date: 2013-5-23-下午5:55:10<br/>
     * <p>
     * 
     * @param e
     * @return
     * 
     */
    protected Map<String, String> packageUppException(UppException e)
    {
        handleException(e);

        Map<String, String> map = new HashMap<String, String>(4);
        map = packageAjaxReturnMap(ERROR_VALUE_OP_RESULT_FAIL, ERROR_VALUE_MSG_TYPE_ERROR, "", e.getMessage());

        return map;
    }

    /**
     * 异常封装 <br/>
     * <p>
     * Description: 将繁琐的异常捕获用一个统一的方法来封装并返回封装后的Map <br/>
     * <p>
     * Author: yun<br/>
     * <p>
     * Date: 2013-5-23-下午5:55:10<br/>
     * <p>
     * 
     * @param e
     * @return
     * 
     */
    protected Map<String, String> packageException(Exception e)
    {
        handleException(e);

        Map<String, String> map = new HashMap<String, String>(4);

        if (e instanceof ParseException)
        {
            map = packageAjaxReturnMap(ERROR_VALUE_OP_RESULT_FAIL, ERROR_VALUE_MSG_TYPE_ERROR, "ParseException", "");
        }
        else
        {
            map = packageAjaxReturnMap(ERROR_VALUE_OP_RESULT_FAIL, ERROR_VALUE_MSG_TYPE_ERROR, "UnknowException", "");
        }

        return map;
    }

    /**
     * 普通异常处理 <br/>
     * <p>
     * Description: 记录日志、不封装、不返回对象 <br/>
     * <p>
     * Author: yun<br/>
     * <p>
     * Date: 2013-5-24-上午9:23:52<br/>
     * <p>
     * 
     * @param e
     * 
     */
    protected void handleException(Exception e)
    {
        _log.error(ExceptionUtils.getStackTrace(e));
    }

    /**
     * @Fields ERROR_KEY_MSG_TYPE : 返回值的key msgType
     */
    public static final String ERROR_KEY_MSG_TYPE                 = "msgType";

    /**
     * @Fields ERROR_KEY_MSG_DESC : 返回值的key msgDesc
     */
    public static final String ERROR_KEY_MSG_DESC                 = "msgDesc";

    /**
     * @Fields ERROR_KEY_OP_RESULT : 返回值的key opResult
     */
    public static final String ERROR_KEY_OP_RESULT                = "opResult";

    /**
     * @Fields ERROR_VALUE_MSG_TYPE_INFO : 返回值的value 消息
     */
    public static final String ERROR_VALUE_MSG_TYPE_INFO          = "info";

    /**
     * @Fields ERROR_VALUE_MSG_TYPE_WARN : 返回值的value 警告
     */
    public static final String ERROR_VALUE_MSG_TYPE_WARN          = "warning";

    /**
     * @Fields ERROR_VALUE_MSG_TYPE_QUESTION : 返回值的value 疑问
     */
    public static final String ERROR_VALUE_MSG_TYPE_QUESTION      = "question";

    /**
     * @Fields ERROR_VALUE_MSG_TYPE_ERROR : 返回值的value 错误
     */
    public static final String ERROR_VALUE_MSG_TYPE_ERROR         = "error";

    /**
     * @Fields ERROR_VALUE_OP_RESULT_SUCCESS : 返回值操作结果 成功
     */
    public static final String ERROR_VALUE_OP_RESULT_SUCCESS      = "0";

    /**
     * @Fields ERROR_VALUE_OP_RESULT_FAIL : 返回值操作结果 失败
     */
    public static final String ERROR_VALUE_OP_RESULT_FAIL         = "1";

    /**
     * @Fields ZTREE_ROOT_VALUE : ztree 根节点的值
     */
    public static final String ZTREE_ROOT_NODE_VALUE              = "-1";

    /**
     * @Fields ERROR_VALUE_OP_RESULT_SUCCESS_NAME : 获取操作结果 成功字段
     */
    public static final String ERROR_VALUE_OP_RESULT_SUCCESS_NAME = "Success";
}